package com.jiyongjun.component.core.impl;

import com.jiyongjun.component.core.model.DubboLogContext;
import com.jiyongjun.component.utils.LogContextUtils;
import com.jiyongjun.component.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import static com.jiyongjun.component.enums.LogConstant.LOG_EXCEPTION_KEYWORD;

/**
 * <h2></h2>
 * <h3>描述：</h3>
 *
 * @author yongjun.jyj
 * @since 2022/6/16 16:36
 */
@Activate(group = CommonConstants.PROVIDER, order = -110000)
@Slf4j
public class DubboWatchDogServerFilter implements Filter, Filter.Listener {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (!SpringContextHolder.isInitialized() || checkIsIgnore(invocation)) {
            return invoker.invoke(invocation);
        }

        DubboLogContext dubboLogContext;
        try {
            DubboWatchDogServerTemplate template = SpringContextHolder.getBeanWithCache(DubboWatchDogServerTemplate.class);
            dubboLogContext = template.onDubboEnter(invocation);

            Result result = template.onHandleApiMethodMetadata(invocation, dubboLogContext);
            if (result != null) {
                return result;
            }
        } catch (Throwable e) {
            log.error("{}|记录dubbo日志异常|msg={}", LOG_EXCEPTION_KEYWORD, e.getMessage(), e);
            dubboLogContext = DubboLogContext.NO_OP_CONTEXT;
        }

        try {
            return invoker.invoke(invocation);
        } catch (Throwable e) {
            dubboLogContext.setServiceException(null, e.getMessage(), e).close();
            throw e;
        }
    }

    private boolean checkIsIgnore(Invocation invocation) {
        return LogContextUtils.isAnnotatedApiFilterIgnore(invocation);
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        if (!SpringContextHolder.isInitialized() || checkIsIgnore(invocation)) {
            return;
        }

        try {
            SpringContextHolder.getBeanWithCache(DubboWatchDogServerTemplate.class).onDubboResponse(invocation, appResponse);
        } catch (Throwable e) {
            log.error("{}|记录dubbo日志异常|msg={}", LOG_EXCEPTION_KEYWORD, e.getMessage(), e);
        }
    }

    @Override
    public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
        // todo
    }

}
